package ltd.hxya.novel.book.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import ltd.hxya.novel.book.entity.BookContent;
import ltd.hxya.novel.book.feign.UserFeignService;
import ltd.hxya.novel.book.mapper.BookContentMapper;
import ltd.hxya.novel.book.mapper.BookMapper;
import ltd.hxya.novel.book.service.IBookContentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ltd.hxya.novel.book.service.IBookIndexService;
import ltd.hxya.novel.book.service.IBookService;
import ltd.hxya.novel.book.utils.constant.DatabaseConsts;
import ltd.hxya.novel.book.vo.BookContentVo;
import ltd.hxya.novel.common.constant.rabbit.RabbitConstant;
import ltd.hxya.novel.common.to.book.BookChapterTo;
import ltd.hxya.novel.common.to.book.BookTo;
import ltd.hxya.novel.common.utils.RedisUtils;
import ltd.hxya.novel.common.vo.BookIndexVo;
import ltd.hxya.novel.common.constant.JwtConstant;
import ltd.hxya.novel.common.constant.redis.RedisConstant;
import ltd.hxya.novel.common.exception.NovelGlobalException;
import ltd.hxya.novel.common.bean.ResultEnum;
import ltd.hxya.novel.common.vo.BookContentParam;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * <p>
 * 小说内容表 服务实现类
 * </p>
 *
 * @author hxya
 * @since 2022-09-13
 */
@Service
@Slf4j
public class BookContentServiceImpl extends ServiceImpl<BookContentMapper, BookContent> implements IBookContentService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private IBookIndexService bookIndexService;

    @Autowired
    private BookMapper bookMapper;

    @Autowired
    private UserFeignService userFeignService;

    @Autowired
    private IBookService bookService;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private RedisUtils redisUtils;



    @Override
    public BookContentVo bookContent(BookContentParam param, HttpServletRequest request) {
        //根据bookIndexId从Redis中查询是否收费
        isFreeRead(param);
        //从数据库中根据目录id查询相关信息
        BookContentVo bookContentVo = bookMapper.selectBaseInfoByIndexId(param.getIndexId());

        //查询出小说的正文
        QueryWrapper<BookContent> bookContentQueryWrapper = new QueryWrapper<>();
        bookContentQueryWrapper.eq("index_id",param.getIndexId());
        BookContent bookContent = this.baseMapper.selectOne(bookContentQueryWrapper);
        //查询下一章小说的id
        Map<Integer, String> indexMap = bookIndexService.nextAndPreIndexId(param);
        String preIndexId = indexMap.get(param.getIndexNum() - 1);
        String nextIndexId = indexMap.get(param.getIndexNum() + 1);
        BeanUtils.copyProperties(bookContent,bookContentVo);
        bookContentVo.setPreIndexId(preIndexId);
        bookContentVo.setNextIndexId(nextIndexId);
        bookContentVo.setIndexNum(param.getIndexNum());
        String token = request.getHeader(JwtConstant.TOKEN_HEADER_KEY);
        if (!StringUtils.isEmpty(token)){
            //TODO 如果用户登录，在阅读一章时，修改当前阅读的书的最后章节
            userFeignService.updateReadHistory(param);
        }

        return bookContentVo;
    }

    @Override
    public String getBookContent(String lastChapterId) {
        QueryWrapper<BookContent> contentQueryWrapper = new QueryWrapper<>();
        contentQueryWrapper.eq("index_id",lastChapterId)
                .last(DatabaseConsts.SqlEnum.LIMIT_1.getSql());
        BookContent bookContent = baseMapper.selectOne(contentQueryWrapper);
        return bookContent.getContent();
    }

    @Transactional
    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(RabbitConstant.BOOKCONTENT_ADD_QUEUE),
                    exchange = @Exchange(RabbitConstant.BOOK_EXCHANGE),
                    key = RabbitConstant.BOOKCONTENT_ADD_ROUTING_KEY))
    @RabbitHandler
    public void batchSaveContent(BookTo book, Message message, Channel channel) throws IOException {
        //插入章节索引信息
        List<BookChapterTo> bookChapterTos = book.getBookChapterTos();
        bookChapterTos = bookIndexService.saveBatchIndex(bookChapterTos);
        //插入章节内容
        List<BookChapterTo> finalBookChapterTos = bookChapterTos;
        CompletableFuture.runAsync(()->{
            saveBatch(finalBookChapterTos);
        });

        //更新最新章节id
        CompletableFuture.runAsync(()->{
            bookService.updateLastIndex(finalBookChapterTos);
        });
        //根据id删除redis中的content
        redisDeleteContent(bookChapterTos);
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        channel.basicAck(deliveryTag,true);
    }

    private void redisDeleteContent(List<BookChapterTo> bookChapterTos) {
        List<String> idList = bookChapterTos.stream().map(bookChapterTo -> {
            return bookChapterTo.getIndexId();
        }).collect(Collectors.toList());
        redisUtils.deleteBatch(idList);
    }

    public void saveBatch(List<BookChapterTo> bookChapterTos) {
        log.debug("开始插入章节正文内容");
        long startTime = new Date().getTime();
        //将bookChapterTos封装程entity
        List<BookContent> bookContents = bookChapterTos.stream().map(bookChapterTo -> {
            BookContent bookContent = new BookContent();
            bookContent.setContent(redisUtils.get(RedisConstant.BOOK_CONTENT_KEY+bookChapterTo.getIndexId()));
            bookContent.setIndexId(bookChapterTo.getIndexId());
            bookContent.setId(IdWorker.getIdStr());
            return bookContent;
        }).collect(Collectors.toList());

        this.saveBatch(bookContents);
        log.debug("章节正文插入完成,用时："+(new Date().getTime()-startTime)/1000.0+"秒");
    }

    private void isFreeRead(BookContentParam param) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        String json = valueOperations.get(RedisConstant.BOOK_INDEX_KEY+param.getBookId());
        //判断查询的数据是否为空，如果为空，从数据库查询数据，并将数据添加到Redis中
        if (StringUtils.isEmpty(json)){
            bookIndexService.bookIndex(param.getBookId(),null);
        }
        List<BookIndexVo> bookIndexVos = JSON.parseObject(json, new TypeReference<List<BookIndexVo>>() {
        });
        BookIndexVo bookIndexVo = bookIndexVos.get(param.getIndexNum());

        if (bookIndexVo.getIsVip() !=null &&bookIndexVo.getIsVip()==1) {
            throw new NovelGlobalException(ResultEnum.NOVEL_NOT_FREE.getCode(),ResultEnum.VERIFY_CODE_ERROR.getMsg());
        }
    }
}
